﻿////using System;
////using System.Collections.Generic;
////using System.Linq;
////using System.Text;

////namespace IronTrishul.Compiler
////{
////    public class Lexer
////    {
////        private string myText;
////        private int pos = 0;
////        public Lexer(string text)
////        {
////            myText = text;
////        }

////        public List<Token> Lex()
////        {
////            var length = myText.Length;
////            var tokens = new List<Token>();
////            while (pos < length)
////            {
////                var element = myText[pos];

////                if (element == '{')
////                {
////                    tokens.Add(new Token() { value = myText[pos].ToString(), kind = Kind.OpenBrace, pos = pos });
////                    pos++;
////                }
////                else if (element == '}')
////                {
////                    tokens.Add(new Token() { value = myText[pos].ToString(), kind = Kind.CloseBrace, pos = pos });
////                    pos++;
////                }
////                else if (element == ']')
////                {
////                    tokens.Add(new Token() { value = myText[pos].ToString(), kind = Kind.CloseSquareBrace, pos = pos });
////                    pos++;
////                }
////                else if (element == '[')
////                {
////                    tokens.Add(new Token() { value = myText[pos].ToString(), kind = Kind.OpenSquareBrace, pos = pos });
////                    pos++;
////                }
////                else if (element == '\"')
////                {
////                    tokens.Add(new Token() { value = "\"", pos = pos, kind = Kind.DoubleQuote });
////                    pos++;
////                    tokens.AddRange(lexString()); //all the characters inside the string..
////                }
////                else if (element == ',')
////                {
////                    tokens.Add(new Token() { value = "\"", pos = pos, kind = Kind.Comma });
////                    pos++;
////                }
////                else if (element == '.')
////                {
////                    tokens.Add(new Token() { value = myText[pos].ToString(), kind = Kind.Dot, pos = pos });
////                    pos++;
////                }
////                else if (element == 't')
////                {
////                    //can this a true token?
////                    //it could spell true
////                    if (myText.Substring(pos, 4) == "true")
////                    {
////                        tokens.Add(new Token() { value = "true", kind = Kind.True, pos = pos });
////                        pos += 4;
////                    }
////                    else
////                    {
////                        tokens.Add(new Token() { value = myText[pos].ToString(), kind = Kind.Character, pos = pos });
////                        pos++;
////                    }
////                }
////                else if (element == 'f')
////                {
////                    //can this a true token?
////                    //it could spell true
////                    if (myText.Substring(pos, 5) == "false") //so that we don't have trues or stuff like that
////                    {
////                        tokens.Add(new Token() { value = "false", kind = Kind.False, pos = pos });
////                        pos += 5;
////                    }
////                    else
////                    {
////                        tokens.Add(new Token() { value = myText[pos].ToString(), kind = Kind.Character, pos = pos });
////                        pos++;
////                    }
////                }
////                else if (element == 'n')
////                {
////                    //can this a true token?
////                    //it could spell true
////                    if (myText.Substring(pos, 4) == "null")
////                    {
////                        tokens.Add(new Token() { value = "null", kind = Kind.Null, pos = pos });
////                        pos += 4;
////                    }
////                    else
////                    {
////                        tokens.Add(new Token() { value = myText[pos].ToString(), kind = Kind.Character, pos = pos });
////                        pos++;
////                    }
////                }
////                else if ((element == 'e' || element == 'E') && (myText[pos + 1] == '+' || myText[pos + 1] == '-' || char.IsNumber(myText[pos + 1])))
////                {
////                    //e is an exponent
////                    tokens.Add(new Token() { kind = Kind.Exponent, pos = pos, value = element.ToString() });
////                    pos++;
////                }
////                else if (element == '-')
////                {
////                    tokens.Add(new Token() { kind = Kind.Minus, pos = pos, value = "-" });
////                    pos++;
////                }
////                else if (element == '+')
////                {
////                    tokens.Add(new Token() { kind = Kind.Plus, pos = pos, value = "+" });
////                    pos++;
////                }//TODO: this will probably never get hit..
////                else if (element == '\\')
////                {
////                    //we read the next one.
////                    //TODO: validate that this is an expected escape char
////                    pos++;
////                    tokens.Add(new Token() { value = myText[pos].ToString(), pos = pos - 1, kind = Kind.EscapedCharacter });
////                    pos++;
////                }
////                else if (element == ':')
////                {
////                    tokens.Add(new Token() { value = ":", pos = pos, kind = Kind.Colon });
////                    pos++;
////                }
////                else if (char.IsNumber(element))
////                {
////                    tokens.Add(new Token() { value = element.ToString(), pos = pos, kind = Kind.Digit });
////                    pos++;
////                }
////                else
////                {
////                    tokens.Add(new Token() { value = myText[pos].ToString(), pos = pos - 1, kind = Kind.Character });
////                    pos++;
////                }

////                //ignore any whitespace
////                ignoreWhitespace();
////            }

////            return tokens;
////        }

////        private List<Token> lexString()
////        {
////            var toks = new List<Token>();
////            //we need to lex the chars until the next double quote
////            bool escaped = false;
////            while (pos < myText.Length && myText[pos] != '\"')
////            {
////                if (myText[pos] == '\\')
////                {
////                    //the next char is the escaped character
////                    pos++;
////                    escaped = true;
////                }
////                if (escaped)
////                {
////                    char ch;
////                    if (myText[pos] == 'n')
////                        ch = '\n';
////                    else if (myText[pos] == 'b')
////                        ch = '\b';
////                    else if (myText[pos] == 'f')
////                        ch = '\f';
////                    else if (myText[pos] == 'r')
////                        ch = '\f';
////                    else if (myText[pos] == 't')
////                        ch = '\f';
////                    else if (myText[pos] == 'u')
////                    {
////                        //we need to read the next 4 numbers.
////                        //TODO: this needs to be 4 HEX digits!!!!
////                        ch = Convert.ToChar(int.Parse(myText.Substring(pos + 1, 4)));
////                        pos += 4; //we only advance the 4 digits. the u is advanced outside this if stmt
////                    }
////                    else if (myText[pos] == '\"' || myText[pos] == '\\' || myText[pos] == '/')
////                    {
////                        //for stuff like: " \ /
////                        ch = myText[pos];
////                    }
////                    else
////                    {
////                        //we made a mistake... there was no escaped character...
////                        //we add the actual \ character AND the character after it.
////                        toks.Add(new Token() { kind = Kind.Character, pos = pos - 1, value = "\\" });
////                        ch = myText[pos];
////                    }
////                    toks.Add(new Token() { kind = Kind.Character, pos = pos, value = ch.ToString() });
////                    escaped = false;
////                }
////                else
////                {
////                    toks.Add(new Token() { kind = Kind.Character, pos = pos, value = myText[pos].ToString() });
////                }
////                pos++;
////            }
////            toks.Add(new Token() { kind = Kind.DoubleQuote, pos = pos, value = myText[pos].ToString() });
////            pos++;

////            return toks;
////        }

////        private void ignoreWhitespace()
////        {
////            while (pos < myText.Length && char.IsWhiteSpace(myText[pos]))
////                pos++;
////        }
////    }

////    public class Token
////    {
////        public Kind kind;
////        public int pos;
////        public string value;

////        public override string ToString()
////        {
////            return string.Format("{0} - {1}", kind, value);
////        }
////    }

////    public enum Kind
////    {
////        OpenBrace, //{
////        CloseBrace, //}
////        OpenSquareBrace, //[
////        CloseSquareBrace, //]
////        Comma, //,
////        DoubleQuote, //"
////        EscapedCharacter, // \" \\ \/ \b \f \n \r \t \u<1234>
////        Minus, //-
////        Plus, //+
////        Digit, //1..9
////        Character, // all except escaped
////        Exponent, //e or E
////        Dot, //.
////        True, //true
////        False, //false
////        Null, //null
////        Colon //:
////    }

////}


//using System;
//using System.Collections.Generic;

//using System.Text;
//using System.Diagnostics;
//using System.Reflection;
//using System.Runtime.CompilerServices;
//using JSONDotNET.Syntax;

//namespace JSONDotNET
//{
//    public class Parser
//    {
//        public static CompilationUnit ParseText(string text)
//        {
//            return new Parser(new Lexer(text).Lex()).Parse();
//        }
//        private List<Token> toks;
//        public Parser(List<Token> toks)
//        {
//            this.toks = toks;
//        }

//        int tokPos = 0;

//        public CompilationUnit Parse()
//        {
//            if (peekToken().kind != Kind.OpenBrace)
//            {
//                throw new ParserException(string.Format("Expected {0} found {1}", Kind.OpenBrace, peekToken().kind), peekToken().pos);
//            }
//            else
//            {
//                return new CompilationUnit() { Unit = parseObject() };
//            }
//        }
//        private ParsedObject parseObject()
//        {
//            Debug.Assert(peekToken().kind == Kind.OpenBrace, "Object should start with {");
//            if (peekToken().kind != Kind.OpenBrace)
//                throw new ParserException(string.Format("Object should start with {0} found {1}", Kind.OpenBrace, peekToken().kind), peekToken().pos);

//            //we eat the { token
//            eatToken();

//            //we parse the members
//            ParsedObject po = new ParsedObject();
//            po.Members = parseMembers();

//            Debug.Assert(peekToken().kind == Kind.CloseBrace, "Object should end with }");
//            if (peekToken().kind != Kind.CloseBrace)
//                throw new ParserException(string.Format("Object should end with {0} found {1}", Kind.CloseBrace, peekToken().kind), peekToken().pos);

//            //we eat the } token
//            eatToken();

//            return po;
//        }
//        private List<ParsedPair> parseMembers()
//        {
//            //the members are like> string : value, string : value
//            var members = new List<ParsedPair>();

//            while (peekToken().kind != Kind.CloseBrace)
//            {
//                members.Add(parsePair());

//                //do we have a comma
//                if (peekToken().kind == Kind.Comma)
//                    //eat it
//                    eatToken();
//            }

//            return members;
//        }
//        private ParsedPair parsePair()
//        {
//            Debug.Assert(peekToken().kind == Kind.DoubleQuote, "A pair starts with a string");
//            if (peekToken().kind != Kind.DoubleQuote)
//                throw new ParserException(string.Format("A pair should start with a {0}, found {1}", Kind.DoubleQuote, peekToken().kind), peekToken().pos);

//            ParsedPair pp = new ParsedPair();
//            pp.Name = parseStringConstruct();

//            Debug.Assert(peekToken().kind == Kind.Colon, "The name is separated from the value by a colon");
//            if (peekToken().kind != Kind.Colon)
//                throw new ParserException(string.Format("The name is separated from the value by {0}, found {1}", Kind.Colon, peekToken().kind), peekToken().pos);

//            //we eat the colon
//            eatToken();

//            //parse the value
//            pp.Value = parseValue();

//            return pp;
//        }
//        private ParsedValue parseValue()
//        {
//            var tok = peekToken();

//            if (tok.kind == Kind.DoubleQuote) //parse string
//                return parseString();
//            else if (tok.kind == Kind.OpenBrace) //parse object
//                return parseObject();
//            else if (tok.kind == Kind.OpenSquareBrace) //parse array
//                return parseArray();
//            //TODO: parse negative,positive numbers
//            else if (tok.kind == Kind.Digit || tok.kind == Kind.Minus) //parse number 
//                return parseNumber();
//            else if (tok.kind == Kind.False) //parse false literal
//                return parseFalseValue();
//            else if (tok.kind == Kind.True) //parse true literal
//                return parseTrueValue();
//            else if (tok.kind == Kind.Null) //parse null literal
//                return parseNullValue();

//            throw new ParserException(string.Format("Value not recognized: {0}", tok.kind), tok.pos);
//        }
//        private ParsedValue parseFalseValue()
//        {
//            Debug.Assert(peekToken().kind == Kind.False);
//            if (peekToken().kind != Kind.False)
//                throw new ParserException(string.Format("Expected {0}, found {1}", Kind.False, peekToken().kind), peekToken().pos);

//            eatToken();
//            return new FalseValue();
//        }
//        private ParsedValue parseTrueValue()
//        {
//            Debug.Assert(peekToken().kind == Kind.True);
//            if (peekToken().kind != Kind.True)
//                throw new ParserException(string.Format("Expected {0}, found {1}", Kind.True, peekToken().kind), peekToken().pos);

//            eatToken();
//            return new TrueValue();
//        }
//        private ParsedValue parseNullValue()
//        {
//            Debug.Assert(peekToken().kind == Kind.Null);
//            if (peekToken().kind != Kind.Null)
//                throw new ParserException(string.Format("Expected {0}, found {1}", Kind.Null, peekToken().kind), peekToken().pos);

//            eatToken();
//            return new NullValue();
//        }
//        private StringValue parseString()
//        {
//            return new StringValue() { Value = parseStringConstruct() };
//        }
//        private NumberValue parseNumber()
//        {
//            bool negative = false;
//            //if we have a -
//            if (peekToken().kind == Kind.Minus)
//            {
//                negative = true;
//                eatToken();
//            }

//            Debug.Assert(peekToken().kind == Kind.Digit, "A number starts with a digit");
//            if (peekToken().kind != Kind.Digit)
//                throw new ParserException(string.Format("Expected {0}, found {1}", Kind.Digit, peekToken().kind), peekToken().pos);

//            double number = 0;
//            Token tok = null;

//            double fracPart = 0;
//            double exponent = double.NaN;

//            while (peekToken().kind == Kind.Digit)
//            {
//                tok = eatToken();
//                number = number * 10 + int.Parse(tok.value);
//            }

//            if (peekToken().kind == Kind.Dot)
//            {
//                //it is like 1.200
//                eatToken();

//                //we must have a number
//                Debug.Assert(peekToken().kind == Kind.Digit);
//                if (peekToken().kind != Kind.Digit)
//                    throw new ParserException(string.Format("Expected {0}, found {1}", Kind.Digit, peekToken().kind), peekToken().pos);

//                //we need to build the fraction part
//                int count = 0;
//                while (peekToken().kind == Kind.Digit)
//                {
//                    tok = eatToken();
//                    count++;
//                    fracPart = fracPart * 10 + double.Parse(tok.value);
//                }

//                fracPart = fracPart / Math.Pow(10, count);
//                number += fracPart;
//            }

//            //we might also have an exponent for the number
//            if (peekToken().kind == Kind.Exponent)
//            {
//                //after the exponent, we need to read the sign

//                eatToken();

//                Debug.Assert(peekToken().kind == Kind.Minus || peekToken().kind == Kind.Plus);
//                if (peekToken().kind != Kind.Minus && peekToken().kind != Kind.Plus)
//                    throw new ParserException(string.Format("Expected {0} or {1}, found {2}", Kind.Plus, Kind.Minus, peekToken().kind), peekToken().pos);

//                tok = eatToken();
//                //now that we know we have an exponent
//                exponent = 0;
//                bool positive;
//                if (tok.kind == Kind.Plus)
//                    positive = true;
//                else
//                    positive = false;

//                //we now need to read the exponent value
//                //we must have a number
//                Debug.Assert(peekToken().kind == Kind.Digit);
//                if (peekToken().kind != Kind.Digit)
//                    throw new ParserException(string.Format("Expected {0}, found {1}", Kind.Digit, peekToken().kind), peekToken().pos);

//                //we need to build the exponent part
//                while (peekToken().kind == Kind.Digit)
//                {
//                    tok = eatToken();
//                    exponent = exponent * 10 + double.Parse(tok.value);
//                }

//                if (positive)
//                    number = number * Math.Pow(10, exponent);
//                else
//                    number = number / Math.Pow(10, exponent);

//                //need to build the number from the exponent
//            }

//            if (fracPart == 0 && double.IsNaN(exponent))
//                return new IntNumberValue() { Value = negative ? -(int)number : (int)number }; //no loss
//            else
//                return new DoubleNumberValue() { Value = negative ? -number : number };
//        }
//        private ParsedValue parseArray()
//        {
//            Debug.Assert(peekToken().kind == Kind.OpenSquareBrace, "An array starts with [");
//            if (peekToken().kind != Kind.OpenSquareBrace)
//                throw new ParserException(string.Format("An array should start with {0}, found {1}", Kind.OpenSquareBrace, peekToken().kind), peekToken().pos);

//            //we eat the [
//            eatToken();
//            ArrayValue av = new ArrayValue();

//            av.Value = new List<ParsedValue>();

//            //an array consists of values separated by commas
//            while (peekToken().kind != Kind.CloseSquareBrace)
//            {
//                av.Value.Add(parseValue());
//                if (peekToken().kind == Kind.Comma)
//                    eatToken();
//            };

//            Debug.Assert(peekToken().kind == Kind.CloseSquareBrace, "An array ends with ]");
//            if (peekToken().kind != Kind.CloseSquareBrace)
//                throw new ParserException(string.Format("An array should end with {0}, found {1}", Kind.CloseSquareBrace, peekToken().kind), peekToken().pos);

//            //eat the ]
//            eatToken();

//            return av;
//        }
//        private string parseStringConstruct()
//        {
//            Debug.Assert(peekToken().kind == Kind.DoubleQuote, "A string should start with \"");
//            if (peekToken().kind != Kind.DoubleQuote)
//                throw new ParserException(string.Format("A string should start with {0}, found {1}", Kind.DoubleQuote, peekToken().kind), peekToken().pos);

//            //we eat the "
//            eatToken();

//            StringBuilder val = new StringBuilder();
//            while ((peekToken()).kind != Kind.DoubleQuote)
//            {
//                var token = eatToken();
//                val.Append(token.value);
//            }

//            Debug.Assert(peekToken().kind == Kind.DoubleQuote, "A string should end with \"");
//            if (peekToken().kind != Kind.DoubleQuote)
//                throw new ParserException(string.Format("An array should end with {0}, found {1}", Kind.DoubleQuote, peekToken().kind), peekToken().pos);

//            //we eat the "
//            eatToken();

//            return val.ToString();
//        }

//        private Token eatToken()
//        {
//            if (toks.Count > 0)
//            {
//                var temp = toks[0];
//                toks.RemoveAt(0);
//                return temp;
//            }

//            return null;
//        }
//        private Token peekToken()
//        {
//            if (toks.Count > 0)
//                return toks[0];

//            return null;
//        }
//    }
//}


